/**
 * 火山引擎图片上传工具类
 * 基于火山引擎对象存储 Browser.js SDK 实现
 * 文档：https://www.volcengine.com/docs/508/66132
 */

// 导入 TOS SDK 类型
interface TOSClient {
  putObject: (params: {
    key: string;
    body: File | Blob;
    headers?: Record<string, string>;
  }) => Promise<any>;
  uploadFile: (params: {
    key: string;
    file: File;
    partSize?: number;
    onProgress?: (progress: { percent: number }) => void;
  }) => Promise<any>;
}

interface STSToken {
  AccessKeyId: string;
  SecretAccessKey: string;
  SessionToken: string;
  ExpiredTime: string;
}

interface UploadOptions {
  /** 上传进度回调 */
  onProgress?: (percent: number) => void;
  /** 自定义文件名 */
  customFileName?: string;
  /** 存储目录 */
  directory?: string;
}

/**
 * 图片上传结果
 */
export interface ImageUploadResult {
  /** 上传是否成功 */
  success: boolean;
  /** 错误信息 */
  error?: string;
  /** 图片URL */
  url?: string;
  /** 图片URI (不包含域名的路径) */
  uri?: string;
}

/**
 * 火山引擎图片上传工具类
 */
export class ImageUploader {
  private client: TOSClient | null = null;
  private region: string;
  private endpoint: string;
  private bucket: string;
  private baseUrl: string;
  private stsToken: STSToken | null = null;
  private initialized = false;

  /**
   * 创建图片上传器实例
   * @param region 区域，例如：'cn-beijing'
   * @param endpoint 终端节点，例如：'tos-cn-beijing.volces.com'
   * @param bucket 存储桶名称
   * @param baseUrl 图片访问的基础URL
   */
  constructor(region: string, endpoint: string, bucket: string, baseUrl: string) {
    this.region = region;
    this.endpoint = endpoint;
    this.bucket = bucket;
    this.baseUrl = baseUrl;
  }

  /**
   * 初始化上传客户端
   * @param stsToken STS临时凭证
   * @returns 是否初始化成功
   */
  public async initialize(stsToken: STSToken): Promise<boolean> {
    try {
      this.stsToken = stsToken;

      // 确保TOS SDK已加载
      if (typeof window.TOS === 'undefined') {
        // 动态加载TOS SDK
        await this.loadTOSSDK();
      }

      // 创建TOS客户端
      this.client = new window.TOS({
        region: this.region,
        endpoint: this.endpoint,
        accessKeyId: stsToken.AccessKeyId,
        accessKeySecret: stsToken.SecretAccessKey,
        stsToken: stsToken.SessionToken,
        bucket: this.bucket,
      });

      this.initialized = true;
      return true;
    } catch (error) {
      console.error('初始化图片上传客户端失败:', error);
      return false;
    }
  }

  /**
   * 动态加载TOS SDK
   */
  private loadTOSSDK(): Promise<void> {
    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      script.src = 'https://tos-public.volccdn.com/obj/volc-tos-public/@volcengine/tos-sdk@latest/browser/tos.umd.production.min.js';
      script.async = true;
      script.onload = () => resolve();
      script.onerror = () => reject(new Error('加载TOS SDK失败'));
      document.body.appendChild(script);
    });
  }

  /**
   * 检查是否已初始化
   */
  private checkInitialized(): boolean {
    if (!this.initialized || !this.client) {
      console.error('图片上传客户端未初始化，请先调用initialize方法');
      return false;
    }
    return true;
  }

  /**
   * 检查STS Token是否过期
   */
  private isTokenExpired(): boolean {
    if (!this.stsToken) return true;
    
    const expiredTime = new Date(this.stsToken.ExpiredTime).getTime();
    const now = new Date().getTime();
    
    // 如果过期时间小于当前时间或者剩余有效期小于5分钟，则认为token已过期
    return expiredTime <= now || expiredTime - now < 5 * 60 * 1000;
  }

  /**
   * 生成唯一的文件名
   * @param file 文件对象
   * @param customFileName 自定义文件名
   * @returns 生成的文件名
   */
  private generateFileName(file: File, customFileName?: string): string {
    if (customFileName) {
      return customFileName;
    }

    const ext = file.name.split('.').pop() || '';
    const timestamp = new Date().getTime();
    const random = Math.floor(Math.random() * 10000);
    return `${timestamp}_${random}.${ext}`;
  }

  /**
   * 上传图片
   * @param file 图片文件
   * @param options 上传选项
   * @returns 上传结果
   */
  public async uploadImage(file: File, options?: UploadOptions): Promise<ImageUploadResult> {
    if (!this.checkInitialized()) {
      return { success: false, error: '上传客户端未初始化' };
    }

    if (this.isTokenExpired()) {
      return { success: false, error: 'STS Token已过期，请重新获取' };
    }

    try {
      // 生成文件名
      const fileName = this.generateFileName(file, options?.customFileName);
      
      // 构建存储路径
      const directory = options?.directory ? `${options.directory.replace(/\/$/, '')}/` : '';
      const key = `${directory}${fileName}`;

      // 根据文件大小选择上传方式
      let result;
      if (file.size > 5 * 1024 * 1024) { // 大于5MB使用分片上传
        result = await this.client!.uploadFile({
          key,
          file,
          partSize: 5 * 1024 * 1024, // 5MB分片
          onProgress: options?.onProgress ? (progress) => {
            options.onProgress!(progress.percent);
          } : undefined,
        });
      } else { // 小于5MB使用普通上传
        result = await this.client!.putObject({
          key,
          body: file,
        });
      }

      // 构建访问URL
      const uri = key;
      const url = `${this.baseUrl}/${uri}`;

      return {
        success: true,
        url,
        uri,
      };
    } catch (error) {
      console.error('上传图片失败:', error);
      return {
        success: false,
        error: error instanceof Error ? error.message : '上传失败',
      };
    }
  }

  /**
   * 批量上传图片
   * @param files 图片文件数组
   * @param options 上传选项
   * @returns 上传结果数组
   */
  public async uploadImages(files: File[], options?: UploadOptions): Promise<ImageUploadResult[]> {
    const results: ImageUploadResult[] = [];
    
    for (const file of files) {
      const result = await this.uploadImage(file, options);
      results.push(result);
    }
    
    return results;
  }
}

// 为Window对象添加TOS类型
declare global {
  interface Window {
    TOS: new (config: {
      region: string;
      endpoint: string;
      accessKeyId: string;
      accessKeySecret: string;
      stsToken: string;
      bucket: string;
    }) => TOSClient;
  }
}

// 导出默认实例
export default ImageUploader;